home *** CD-ROM | disk | FTP | other *** search
- /*{{{}}}*/
- /*{{{ #includes*/
- #ifdef CONFIG_H
- # include "config.h"
- #endif
-
- #include <sys/types.h>
- #include <ctype.h>
- #include <string.h>
- #include <limits.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
-
- #define VIRTUAL_C
- #define I_LOOP_C
- #define I_FOLDING_C
- #define I_GETMSG_C
- #define I_MESSAGES_C
- #define I_ORIEDT_C
- #define I_SIGNALS_C
- #define I_STRING_C
-
- #include "origami.h"
- #include <lib/ori_add_lib.h>
- /*}}} */
-
- /*{{{ #ifdef VIRTUAL - additional types,variables and procedures*/
- #ifdef VIRTUAL
-
- /*{{{ constants*/
- # define LINE_PART (BLOCK_SIZE-sizeof(off_t))
- /* number of chars, which can be stored */
- /* in one fileblock */
-
- # define FILE_FREE_COUNT (((int)(LINE_PART/sizeof(int)))-1)
- /* number of file-garbage-entries in a */
- /* virtuell memoryblock (including a link */
- /* to next package) */
- /*}}} */
- /*{{{ typedef VIR_ELEMENT*/
- typedef struct
- { element *parent; /* textnode belonging to this textstring */
- /* nodes[0]: not used */
-
- int pre,next; /* links for doubled linked LRU-list */
- /* nodes[0]: pointer to head and tail of */
- /* lru-list */
-
- int filepo; /* position of the unchanged text in file */
- /* nodes[0]: list of free local buffers */
-
- union
- { unsigned char txt[LINELEN+1];
- /* textline */
- int *fre_f_buff; /* pointer to list of free filebuffers */
- /* (used from nodes[0]) */
- } t;
-
- } VIR_ELEMENT;
- /*}}} */
-
- /*{{{ variables*/
- private VIR_ELEMENT *nodes=0; /* local buffers */
- private off_t old_pos=0;
- private unsigned int file_used; /* number of used fileblocks */
- private int tmp_file; /* file-descriptor for */
- /* temporary file */
- private int file_garbage; /* index for handling free */
- /* file-blocks */
- private char ori_vir_tmp[_POSIX_PATH_MAX+1];
- /* name of tmp-file */
- public int vir_nodes=0; /* number of local buffers */
- /*}}} */
-
- /*{{{ vir_dumb/vprint*/
- # ifdef VIR_DEBUG
- extern FILE *v_dumb;
-
- # define vprintf(f,x) (fprintf(v_dumb,f,x),fflush(v_dumb))
- # define v_format "^^ %s ^^\n"
- /*{{{ vir_dumb*/
- private void vir_dumb(char*t)
- { if (v_dumb)
- { int i;
-
- for (i=0;i<vir_nodes;i++)
- { fprintf(v_dumb,
- "%3d|node %p|f%3d|p%3d|n%3d|%.32s\n",
- i,
- (void*)nodes[i].parent,
- nodes[i].filepo,
- nodes[i].pre,
- nodes[i].next,
- i?nodes[i].t.txt:(unsigned char*)""
- );
- }
- vprintf(v_format,t);
- }
- }
- /*}}} */
- # else
- # define vir_dumb(x)
- # define vprintf(f,x)
- # endif
- /*}}} */
-
- /*{{{ v_error*/
- private void v_error(char const*const s)
- {
- exit_origami(r_vir_err,get_msg(F_VM_FAIL,s,strerror(errno)));
- }
- /*}}} */
- /*{{{ handle the file-blocks, file-IO*/
- /*{{{ seek_tmp seek in tmp-file, arguments: offset*/
- private void seek_tmp(off_t po)
- { if (po!=old_pos && -1==(old_pos=lseek(tmp_file,po,SEEK_SET)))
- v_error("seek");
- }
- /*}}} */
- /*{{{ read_tmp read from tmp-file, arguments: offset,length,*data*/
- private unsigned char *read_tmp(off_t po,int lg,unsigned char * const s)
- { seek_tmp(po);
- if (-1==read(tmp_file,(char *)s,lg))
- v_error("read");
- else
- old_pos+=lg;
-
- return(s);
- }
- /*}}} */
- /*{{{ write_tmp write to tmp-file, drguments: offset,length,*data*/
- private void write_tmp(off_t po,int lg,unsigned char const * const s)
- {
- seek_tmp(po);
- if (-1==write(tmp_file,(char *)s,lg))
- v_error("write");
- else
- old_pos+=lg;
- }
- /*}}} */
-
- /*{{{ get_file_buff get a new file-block (or previously freed one)*/
- private int get_file_buff(void)
- {
- int x;
- int po;
-
- if (file_garbage) {
- /*{{{ get fromlist*/
- x=((int*) nodes[0].t.fre_f_buff)[--file_garbage];
- /*{{{ if list now empty, try to get next part*/
- if (!file_garbage) {
- if ((po=((int*)nodes[0].t.fre_f_buff)[FILE_FREE_COUNT])) {
- /*{{{ next-link was not 0!, so get the package*/
- read_tmp((off_t)(po)*BLOCK_SIZE+sizeof(int),
- LINE_PART,
- (unsigned char*)nodes[0].t.fre_f_buff);
- file_garbage=FILE_FREE_COUNT;
- /*}}} */
- }
- }
- /*}}} */
- return(x);
- /*}}} */
- } else {
- /*{{{ new one*/
- vprintf(v_format,"expand v-file");
- /*{{{ clear the next-pointer in the block!*/
- { int dummy=0;
-
- write_tmp((off_t)(++file_used)*BLOCK_SIZE,sizeof(off_t),(unsigned char*)&dummy);
- }
- vir_debug((off_t)(file_used*BLOCK_SIZE));
- if (!file_used)
- v_error("append");
- /*}}} */
- return(file_used);
- /*}}} */
- }
- }
- /*}}} */
- /*{{{ free_file_buff add a file-block to garbage list*/
- private void free_file_buff(int po)
- {
- /*{{{ if current block of garbage list full, save this part*/
- if (file_garbage==FILE_FREE_COUNT) {
- /*{{{ variables*/
- int block_no;
- /*}}} */
-
- /*{{{ get number for the free-block in file*/
- block_no= *(nodes[0].t.fre_f_buff);
- /*}}} */
- write_tmp((off_t)block_no*BLOCK_SIZE+sizeof(int),
- LINE_PART,
- (unsigned char*) nodes[0].t.fre_f_buff);
- nodes[0].t.fre_f_buff[FILE_FREE_COUNT]=block_no;
- file_garbage=0;
- }
- /*}}} */
- /*{{{ move the free entry to list*/
- nodes[0].t.fre_f_buff[file_garbage++]=po;
- /*}}} */
-
- return;
- }
- /*}}} */
- /*}}} */
- /*{{{ read/write data-lines*/
- /*{{{ get_line_from_file read a textline, argument: first block of line*/
- private void get_line_from_file(int po,unsigned char * const txt)
- {
- /*{{{ variables*/
- unsigned char *s=txt;
- int next;
- off_t current_po=(off_t)(po)*BLOCK_SIZE;
- int lg=LINELEN;
- /*}}} */
-
- /*{{{ read the line to buff*/
- do {
- vprintf("%s","get line");
- /*{{{ read the overflow-index*/
- read_tmp(current_po,sizeof(off_t),(unsigned char*)&next);
- /*}}} */
- /*{{{ read data*/
- read_tmp(current_po+sizeof(off_t),LINE_PART<lg?LINE_PART:lg,s);
- s+=LINE_PART;
- lg-=LINE_PART;
- /*}}} */
- current_po=(off_t)(next)*BLOCK_SIZE;
- } while (next && lg>0);
- *s='\0';
- /*}}} */
- }
- /*}}} */
- /*{{{ put_line_to_file write a textline to file, return first block*/
- private int put_line_to_file(unsigned char const * s)
- {
- /*{{{ variables*/
- int po=get_file_buff();
- off_t current_po=(off_t)(po)*BLOCK_SIZE;
- int l=ustrlen(s);
- int next;
- /*}}} */
-
- do {
- /*{{{ write a part*/
- /*{{{ get old overflow-index of the file-block*/
- read_tmp(current_po,sizeof(off_t),(unsigned char*)&next);
- /*}}} */
- l -= LINE_PART;
- if (l>0) {
- /*{{{ line must be splitted again*/
- /*{{{ write the part*/
- write_tmp(current_po+sizeof(off_t),LINE_PART,s);
- s+=LINE_PART;
- /*}}} */
- if (!next) {
- /*{{{ get new overflow and store it in the fileblock too*/
- next=get_file_buff();
- write_tmp(current_po,sizeof(off_t),(unsigned char*)&next);
- /*}}} */
- }
- current_po = next*BLOCK_SIZE;
- /*}}} */
- } else {
- /*{{{ line is short enough for a packet*/
- if (next) free_file_buff(next);
- next=0;
- write_tmp(current_po,sizeof(off_t),(unsigned char*)&next);
- write_tmp(current_po+sizeof(off_t),l+LINE_PART+(l?1:0),s);
- /*}}} */
- }
- /*}}} */
- } while (l>0);
-
- return(po);
- }
- /*}}} */
- /*}}} */
- /*{{{ handle the local buffer-nodes*/
- /*{{{ lru_handle move a local buffer to top of LRU-list*/
- private void lru_handle(int i)
- {
- int n,p;
-
- nodes[p=nodes[i].pre].next=n=nodes[i].next;
- nodes[n].pre=p;
- nodes[i].pre=0;
- nodes[nodes[i].next=nodes[0].next].pre=i;
- nodes[0].next=i;
- }
- /*}}} */
- /*{{{ get_local_buff return a free local buffer (maybe free one)*/
- private int get_local_buff(void)
- {
- int i,x;
- VIR_ELEMENT *x_ptr;
-
- /*{{{ x=free local-buffer-place,x_ptr=its adress*/
- if ((x=nodes[0].filepo)) {
- /*{{{ free list not empty*/
- x_ptr= &nodes[x];
- /*{{{ remove from free-list*/
- nodes[0].filepo=nodes[x].filepo;
- /*}}} */
- /*{{{ append to head of lru*/
- nodes[x_ptr->next=nodes[0].next].pre=x;
- x_ptr->pre=0;
- nodes[0].next=x;
- /*}}} */
- /*}}} */
- } else {
- /*{{{ make a place free*/
- /*{{{ get a good place to move to file*/
- x=nodes[0].pre;
- /*{{{ not unchanged, so unchange all not fixed buffers*/
- if (!nodes[x].filepo) {
- for (i=((vir_nodes-FIXED-1)>>1)+1;i--;)
- { if (!nodes[x].filepo)
- nodes[x].filepo=put_line_to_file(nodes[x].t.txt);
- x=nodes[x].pre;
- }
- x=nodes[0].pre;
- }
- /*}}} */
- x_ptr= &nodes[x];
- /*}}} */
- /*{{{ set element's data-entry to file-block*/
- x_ptr->parent->datas.posi=x_ptr->filepo;
- /*}}} */
- lru_handle(x);
- /*}}} */
- }
- /*}}} */
- x_ptr->filepo=0;
- vir_dumb("buff get local");
-
- return(x);
- }
- /*}}} */
- /*{{{ free_local_buff add a local buffer to garbage-list*/
- private void free_local_buff(int pos)
- {
- int p,n;
- VIR_ELEMENT *current = &nodes[pos];
-
- /*{{{ if unchanged, free also the file-block*/
- if (current->filepo) free_file_buff(current->filepo);
- /*}}} */
- current->t.txt[0]='\0';
- /*{{{ remove from LRU*/
- nodes[p=current->pre].next=n=current->next;
- nodes[n].pre=p;
- /*}}} */
- /*{{{ put to free locals*/
- current->filepo=nodes[0].filepo;
- nodes[0].filepo=pos;
- /*}}} */
- vir_dumb("buff free local");
-
- return;
- }
- /*}}} */
- /*}}} */
-
- #endif
- /*}}} */
-
- #ifdef VIRTUAL
- /*{{{ init_data_handle init the local buffer and the tmp-file*/
- public int init_data_handle(void)
- {
- if (vir_nodes)
- /*{{{ virtuell linehandling is active, initialise the buffers*/
- { int i;
-
- /*{{{ minimum size of table is checked*/
- if (vir_nodes<=FIXED)
- vir_nodes=FIXED+1;
- /*}}} */
- /*{{{ get the table*/
- if (!(nodes=paket_malloc(vir_nodes*sizeof(VIR_ELEMENT)+LINE_PART)))
- exit_origami(r_mem_full,M_NO_MEMORY);
- /*}}} */
- /*{{{ init the table*/
- /*{{{ normal nodes*/
- for (i=vir_nodes-2;i;i--)
- nodes[i].filepo=i+1;
- nodes[vir_nodes-1].filepo=0;
- /*}}} */
- /*{{{ root-node*/
- nodes[0].pre=0;
- nodes[0].next=0;
- nodes[0].filepo=1;
- nodes[0].t.fre_f_buff=(int*)&nodes[vir_nodes];
- nodes[0].t.fre_f_buff[FILE_FREE_COUNT]=0;
- /*}}} */
- /*}}} */
- file_garbage=0;
- file_used=0;
- /*{{{ open the tmp-file and set to position BLOCK_SIZE*/
- tmpnam(ori_vir_tmp);
- if ((tmp_file=open(ori_vir_tmp,O_RDWR | O_CREAT,0600))<0)
- return(1);
- if (-1==(old_pos=lseek(tmp_file,(off_t) BLOCK_SIZE,SEEK_SET)))
- v_error("seek");
- /*}}} */
- vir_dumb("start");
- }
- /*}}} */
- return(0);
- }
- /*}}} */
- /*{{{ end_data_handle close and unlink tmp-file*/
- public int end_data_handle(void)
- {
- return(vir_nodes && (close(tmp_file) || unlink(ori_vir_tmp)));
- }
- /*}}} */
- #endif
-
- /*{{{ get_data get the data belonging to a node*/
- #ifdef VIRTUAL
- public unsigned char *get_data(element const * const pin)
- { element *p=(element*)pin;
-
- # ifdef VIRTUAL
- if (vir_nodes)
- /*{{{ virtuell linehandling is active*/
- { int i,po;
-
- if ((i=p->datas.posi)==0)
- /*{{{ empty string*/
- { vprintf(v_format,"get empty");
-
- return((unsigned char*)empty_text);
- }
- /*}}} */
- else if (i==-vir_nodes)
- /*{{{ short string*/
- { vprintf(v_format,"get short");
-
- return(p->x.txt);
- }
- /*}}} */
- else if (i<0)
- /*{{{ local buffer*/
- { lru_handle(-i);
- vir_dumb("get local");
-
- return(nodes[-i].t.txt);
- }
- /*}}} */
- else
- /*{{{ get from file*/
- { VIR_ELEMENT *cur;
-
-
- p->datas.posi = -(po=get_local_buff());
- cur = &nodes[po];
- cur->parent=p;
- cur->filepo=i;
- get_line_from_file(i,cur->t.txt);
- vir_dumb("get file");
-
- return(cur->t.txt);
- }
- /*}}} */
- }
- /*}}} */
- # endif
- return(p->datas.dat);
- }
- #else
- /* defined as a macro in origami.h */
- #endif
- /*}}} */
- /*{{{ set_data set the data of a node to new value*/
- public void set_data
- ( element * const p,
- unsigned char const * const s,
- boolean const txt
- )
- { int l;
-
- l=ustrlen(s);
- #ifdef VIRTUAL
- if (vir_nodes)
- /*{{{ virtuell line-handling is active*/
- { int i,po;
-
- /*{{{ i= old position of text*/
- i=p->datas.posi;
- /*}}} */
- if (l>=sizeof(fold_data) || !txt)
- /*{{{ new string must be stored extern (to long or fold))*/
- { if (i<0 && i!=-vir_nodes)
- /*{{{ old in buffer*/
- { VIR_ELEMENT *current = &nodes[-i];
-
- /*{{{ free old data*/
- if (current->filepo) free_file_buff(current->filepo);
- /*}}} */
- ustrcpy(current->t.txt,s);
- current->filepo=0;
- lru_handle(-i);
- vir_dumb("set buff text");
- }
- /*}}} */
- else
- /*{{{ old in file or empty or short*/
- {
- /*{{{ maybe free the filedata*/
- if (i>0) free_file_buff(i);
- /*}}} */
- /*{{{ put data to new local buffer*/
- p->datas.posi = -(po=get_local_buff());
- { VIR_ELEMENT *current = &nodes[po];
-
- current->parent=p;
- ustrcpy(current->t.txt,s);
- current->filepo=0;
- }
- /*}}} */
- vir_dumb("set file/empty text");
- }
- /*}}} */
- }
- /*}}} */
- else
- /*{{{ new string short enough, to be stored in the node*/
- {
- # ifdef VIR_DEBUG
- char *du;
- # endif
-
- /*{{{ handle old data*/
- if (i==0 || i==-vir_nodes)
- /*{{{ ok, both in node*/
- {
- # ifdef VIR_DEBUG
- du=l?"set empty/short short":"set empty/short empty";
- # endif
- }
- /*}}} */
- else if (i<0)
- /*{{{ local, free the local buffer*/
- { free_local_buff(-i);
- # ifdef VIR_DEBUG
- du=l?"set local short":"set local empty";
- # endif
- }
- /*}}} */
- else
- /*{{{ in file, free the filebuffer*/
- { free_file_buff(i);
- # ifdef VIR_DEBUG
- du=l?"set file short":"set file empty";
- # endif
- }
- /*}}} */
- /*}}} */
- /*{{{ set new data*/
- if (l)
- /*{{{ copy to node*/
- { p->datas.posi= -vir_nodes;
- ustrcpy(p->x.txt,s);
- }
- /*}}} */
- else
- /*{{{ mark empty*/
- { p->datas.posi=0;
- }
- /*}}} */
- /*}}} */
- vprintf(v_format,du);
- }
- /*}}} */
- }
- /*}}} */
- else
- #endif
- /*{{{ memory*/
- { unsigned char *to_free;
-
- /*{{{ store, if any memory to free (don't free, maybe new is part of old!)*/
- to_free=p->datas.dat;
- if (to_free==empty_text || to_free==p->x.txt)
- to_free=0;
- /*}}} */
- if (l)
- /*{{{ new string is not empty, malloc and copy*/
- { if
- ( txt
- && l<sizeof(fold_data)
- && ( ( bd.m.select_mode!=fold_selection
- && bd.m.select_mode!=unmark_fold_selection
- )
- || p!=bd.f.select_ptr
- )
- )
- p->datas.dat=p->x.txt;
- else
- if (!(p->datas.dat=ori_malloc(l+1)))
- exit_origami(r_mem_full,M_NO_MEMORY);
- ustrcpy(p->datas.dat,s);
- }
- /*}}} */
- else
- /*{{{ empty text, use default empty-text-pointer*/
- p->datas.dat=(unsigned char*)empty_text;
- /*}}} */
- if (to_free)
- paket_free(to_free);
- }
- /*}}} */
- }
- /*}}} */
- /*{{{ set_0_data set the data of a node to empty*/
- public void set_0_data(element * const p)
- {
-
- #ifdef VIRTUAL
- if (vir_nodes)
- set_data(p,empty_text,False);
- else
- #endif
- /*{{{ memory*/
- { if (p->datas.dat!=empty_text && p->datas.dat!=p->x.txt)
- paket_free(p->datas.dat);
- p->datas.dat=(unsigned char*)empty_text;
- }
- /*}}} */
- }
- /*}}} */
- /*{{{ new_data create empty data for a new malloced node*/
- #ifdef VIRTUAL
- /*{{{ comment*/
- /* new_data can be used more than once for the same node */
- /* only if set-data is used for a node, a call of new_data will destroy */
- /* the garbage-collection-data. */
- /*}}} */
- public void new_data(element *p)
- {
- # ifdef VIRTUAL
- if (vir_nodes)
- /*{{{ virtual*/
- { p->datas.posi=0;
-
- vprintf(v_format,"new");
- }
- /*}}} */
- else
- # endif
- /*{{{ memory*/
- p->datas.dat=(unsigned char*)empty_text;
- /*}}} */
- }
- #else
- /* defined as a macro in origami.h */
- #endif
- /*}}} */
-